package net.mcreator.overglazed.recipe;

import com.mojang.serialization.MapCodec;
import io.netty.buffer.ByteBuf;
import net.minecraft.core.component.DataComponents;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.resources.Identifier;
import net.minecraft.tags.ItemTags;
import net.minecraft.world.item.DyeColor;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.component.DyedItemColor;
import net.minecraft.world.item.crafting.CraftingInput;
import net.minecraft.world.item.crafting.CraftingRecipe;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.world.item.crafting.ItemStackTemplate;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.neoforge.registries.RegisterEvent;

import java.util.ArrayList;
import java.util.List;

public class WineDyeArmorRecipe implements CraftingRecipe {

    private static final int WINE_COLOR = 0x76223A;

    private static final Item WINE_DYE =
            net.minecraft.core.registries.BuiltInRegistries.ITEM.get(
                    Identifier.fromNamespaceAndPath(
                            "overglazed",
                            "wine_dye"
                    )
            );

    private static final List<Item> TARGETS = List.of(
            Items.LEATHER_BOOTS,
            Items.LEATHER_LEGGINGS,
            Items.LEATHER_CHESTPLATE,
            Items.LEATHER_HELMET,
            Items.LEATHER_HORSE_ARMOR,
            Items.WOLF_ARMOR
    );

    public static final MapCodec<WineDyeArmorRecipe> CODEC =
            MapCodec.unit(new WineDyeArmorRecipe());

    public static final StreamCodec<RegistryFriendlyByteBuf, WineDyeArmorRecipe>
            STREAM_CODEC = StreamCodec.unit(new WineDyeArmorRecipe());

    public static final RecipeSerializer<WineDyeArmorRecipe> SERIALIZER =
            new RecipeSerializer<>(CODEC, STREAM_CODEC);

    @SubscribeEvent
    public static void register(RegisterEvent event) {
        event.register(
                net.minecraft.core.registries.Registries.RECIPE_SERIALIZER,
                Identifier.fromNamespaceAndPath(
                        "overglazed",
                        "wine_dye_armor"
                ),
                () -> SERIALIZER
        );
    }

    @Override
    public boolean matches(
            CraftingInput input,
            net.minecraft.world.level.Level level
    ) {
        boolean foundTarget = false;
        boolean foundDye = false;

        for (int i = 0; i < input.size(); i++) {
            ItemStack stack = input.getItem(i);

            if (stack.isEmpty()) {
                continue;
            }

            if (TARGETS.contains(stack.getItem())) {
                if (foundTarget) {
                    return false;
                }

                foundTarget = true;
                continue;
            }

            if (stack.is(WINE_DYE) || stack.is(ItemTags.DYES)) {
                foundDye = true;
                continue;
            }

            return false;
        }

        return foundTarget && foundDye;
    }

    @Override
    public ItemStack assemble(CraftingInput input) {
        ItemStack target = ItemStack.EMPTY;
        List<Integer> colors = new ArrayList<>();

        for (int i = 0; i < input.size(); i++) {
            ItemStack stack = input.getItem(i);

            if (stack.isEmpty()) {
                continue;
            }

            if (TARGETS.contains(stack.getItem())) {
                target = stack;
                continue;
            }

            if (stack.is(WINE_DYE)) {
                colors.add(WINE_COLOR);
                continue;
            }

            if (stack.is(ItemTags.DYES)) {
                DyeColor dye = stack.get(DataComponents.DYE);

                if (dye != null) {
                    colors.add(dye.getTextureDiffuseColor());
                }
            }
        }

        if (target.isEmpty() || colors.isEmpty()) {
            return ItemStack.EMPTY;
        }

        /*
         * Start with the existing color of the armor.
         * Undyed leather uses vanilla's leather base color.
         */
        int oldColor = DyedItemColor.getOrDefault(
                target,
                DyedItemColor.LEATHER_COLOR
        );

        int totalR = (oldColor >> 16) & 255;
        int totalG = (oldColor >> 8) & 255;
        int totalB = oldColor & 255;

        int totalMax = Math.max(
                totalR,
                Math.max(totalG, totalB)
        );

        int count = 1;

        for (int color : colors) {
            int r = (color >> 16) & 255;
            int g = (color >> 8) & 255;
            int b = color & 255;

            totalR += r;
            totalG += g;
            totalB += b;

            totalMax += Math.max(
                    r,
                    Math.max(g, b)
            );

            count++;
        }

        int averageR = totalR / count;
        int averageG = totalG / count;
        int averageB = totalB / count;

        int averageMax = Math.max(
                averageR,
                Math.max(averageG, averageB)
        );

        if (averageMax > 0) {
            averageR = averageR * totalMax / (count * averageMax);
            averageG = averageG * totalMax / (count * averageMax);
            averageB = averageB * totalMax / (count * averageMax);
        }

        averageR = Math.max(0, Math.min(255, averageR));
        averageG = Math.max(0, Math.min(255, averageG));
        averageB = Math.max(0, Math.min(255, averageB));

        int resultColor =
                (averageR << 16) |
                (averageG << 8) |
                averageB;

        ItemStack result = target.copy();

        result.set(
                DataComponents.DYED_COLOR,
                new DyedItemColor(resultColor)
        );

        result.setCount(1);

        return result;
    }

    @Override
    public RecipeSerializer<? extends CraftingRecipe> getSerializer() {
        return SERIALIZER;
    }

    @Override
    public RecipeType<? extends CraftingRecipe> getType() {
        return RecipeType.CRAFTING;
    }

    @Override
    public ItemStack getResultItem(
            net.minecraft.core.HolderLookup.Provider registries
    ) {
        return new ItemStack(Items.LEATHER_HELMET);
    }

    @Override
    public boolean canCraftInDimensions(int width, int height) {
        return width * height >= 2;
    }
}